/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.devs.benchmark.topology;

import java.util.List;
import org.devs.benchmark.Util;
import org.devs.benchmark.modeling.CoupledType;
import org.devs.benchmark.modeling.ModelType;

/**
 *
 * @author Alejandro Moreno
 */
public class CordonalRing extends Network {

    int perimeter;
    int connectivity;

    public CordonalRing(String name, int perimeter, int connectivity, Class message, int recursion) throws Exception {
        super(name,message,recursion);
        this.perimeter = perimeter;
        this.connectivity = connectivity;

        if ((perimeter * connectivity % 2 != 0) || (perimeter < 1) || (connectivity > (perimeter - 1)) || (connectivity < 2) || (recursion <1)) {
            throw new Exception("Parameters are incorrect");
        }
        

    }

    

    public CordonalRing(String name, int perimeter, int connectivity, Class message) throws Exception {
        super(name, message);

        this.perimeter = perimeter;
        this.connectivity = connectivity;

        if ((perimeter * connectivity % 2 != 0) || (perimeter < 1) || (connectivity > (perimeter - 1)) || (connectivity < 2)) {
            throw new Exception("Parameters are incorrect");
        }


    }

    
    public void buildModel(){
        
        super.setModel(this.createNetwork(this.name, this.perimeter, this.connectivity, super.message, super.recursion));
    }


    public void connectNodes(CoupledType coupled, int connectivity) {


        if (coupled.getModels().size() > 0) {

            List<ModelType> models = coupled.getModels();

            for (int i = 0; i < connectivity; i++) {
                addConnectionToParent(coupled, 0, i, i);
                addConnectionFromParent(coupled, 0, i, i);
            }

            int[] nodes = new int[models.size()];

            for (int i = 1; i <= (connectivity / 2); i++) {

                int index = 0;
                for (int j = 0; j < Util.gcd(models.size(), i); j++) {

                    int k = index;

                    do {
                        int q = (k + i) % models.size();

                        addConnection(coupled, k, nodes[k], q, nodes[q]);
                        addConnection(coupled, q, nodes[q], k, nodes[k]);

                        nodes[q]++;
                        nodes[k]++;
                        k = q;

                    } while (k != index);

                    index = (index + 1);
                }

            }

            if (connectivity % 2 != 0) {

                for (int i = 0; i < (models.size()/2); i++) {

                    int q = (i + (models.size() / 2));
                    addConnection(coupled, i, nodes[i], q, nodes[q]);
                    addConnection(coupled, q, nodes[q], i, nodes[i]);
                    nodes[i]++;
                    nodes[q]++;

                }

            }

        }

    }

    public ModelType createNetwork(String name, int length,int connectivity, Class message, int recursion) {
        return create(name, length,connectivity, "", message, recursion);
    }



    public ModelType create(String name, int length,int connectivity, String id,Class message, int recursion) {

        CoupledType coupled = null;

        if (recursion > 0) {

            coupled = new CoupledType(name + "_Coupled" + id, Util.createInports(connectivity, message), Util.createOutports(connectivity, message));

            for (int j = 0; j < length; j++) {

                coupled.getModels().add(create(name, length,connectivity, id + "_" + j, message, recursion - 1));

            }

            

            connectNodes(coupled, connectivity);

        } else {


            coupled = buildNode(name, connectivity, message, id);


        }

        return coupled;

    }

    
}
